#ifndef _SERIALIZABLE_H_
#define _SERIALIZABLE_H_

#include <string>
#include <stdexcept>
#include "Util.h"

namespace SEngine
{

    template<typename T>
    struct Serializer
    {
        std::string Serialize(T & object) { static_assert(false, __FUNCTION__ " is not impl!"); }
        void Deserialize(const std::string&, T & object) { static_assert(false, __FUNCTION__ " is not impl!"); }
    };
    
    #define ENABLE_SERIALIZE_BASE  \
        template<typename Serializers> \
        std::string Serialize(Serializers loader) { \
            std::string out; \
            ForeachType([this, &out](auto load) { \
                using Type = TYPELOADER_TYPE(load); \
                if (typeid(*this).hash_code() == typeid(Type).hash_code()) { \
                    out = static_cast<Type&>(*this).Serialize(); \
                } \
            }, loader); \
            return out; \
        } \
        template<typename Serializers> \
        void Deserialize(const std::string & str, Serializers loader) { \
            ForeachType([this, &out](auto load) { \
                using Type = TYPELOADER_TYPE(load); \
                if (typeid(*this).hash_code() == typeid(Type).hash_code()) { \
                    static_cast<Type&>(*this).Deserialize(str); \
                } \
            }, loader); \
        }
    
    #define ENABLE_SERIALIZE(class) \
        friend Serializer<class>; \
        template<typename Ser = Serializer<class>>\
        std::string Serialize(Ser serializer = Serializer<class>()) {\
            return serializer.Serialize(*this);\
        }\
        template<typename Ser = Serializer<class>>\
        void Deserialize(const std::string & str, Ser & serializer = Serializer<class>()) {\
            serializer.Deserialize(str, *this);\
        }


} // namespace SEngine


#endif